S11-03 Vue-路由
[TOC]
API-Vue Router
概述
路由发展
- 后端路由阶段
- 前后端分离阶段
- 单页面富应用(SPA)
后端路由阶段
服务端渲染:服务器直接渲染好对应的HTML页面, 返回给客户端进行展示。
服务端渲染流程:
- 一个页面有自己对应的网址, 也就是URL。
- URL会发送到服务器, 服务器会通过正则对该URL进行匹配, 并且最后交给一个Controller进行处理。
- Controller进行各种处理, 最终生成HTML或者数据, 返回给前端。
优点:
- 1、渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示。
- 2、有利于SEO的优化。
缺点:
- 整个页面的模块由后端人员来编写和维护。
- 前端开发人员如果要开发页面, 需要通过PHP和Java等语言来编写页面代码。
- HTML代码和数据以及对应的逻辑会混在一起, 编写和维护困难。
前后端分离阶段
前后端分离:后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JS将数据渲染到页面中。
优点:
- 前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化。
- 当移动端(iOS/Android)出现后,后端不需要进行任何处理,依然使用之前的一套API。
路由模式
- URL的hash
- HTML5的History
URL的hash
URL的hash:也就是锚点(#
), 本质上是改变window.location
的href属性。我们可以通过直接赋值location.hash
来改变href, 但是页面不发生刷新。
优点:兼容性更好,在老版IE中都可以运行
缺点:有一个#
,显得不像一个真实的路径
示例:
HTML5的History
history接口是HTML5新增的, 它有六种模式改变URL而不刷新页面
history.pushState():(state,title?,url?)
,用于将一个新的历史记录条目添加到浏览器的历史记录栈中,而不会刷新页面。
history.replaceState():(state,title?,url?)
,用于替换当前浏览器历史记录中的条目。
history.back():()
,用于让浏览器回到历史记录中的前一个页面。可理解为模拟用户点击浏览器的“后退”按钮。
history.forward():()
,用于让浏览器前进到历史记录中的下一个页面。可理解为模拟用户点击浏览器的“前进”按钮。
history.go():(delta)
,用于在浏览器历史记录栈中进行前进或后退操作。
示例:
基础
vue-router概述
目前前端流行的三大框架, 都有自己的路由实现:Angular的ngRouter,React的ReactRouter,Vue的vue-router
vue-router是基于路由和组件的:
- 路由用于设定访问路径, 将路径和组件映射起来。
- 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换
安装
方式一:直接安装
# 直接安装4.x版本的vue-router
npm install vue-router@4
方式二:使用create-vue创建Vue项目时选择安装
# 1. 使用create-vue创建Vue项目
pnpm create vue
# 2. 在安装选项中选择安装vue-router
基本使用
步骤:
- 1、创建路由组件。
- 2、配置路由映射: 组件和路径映射关系的
routes
数组。 - 3、创建路由对象:通过
createRouter()
创建路由对象,并且传入routes和history模式。 - 4、使用
app.use()
注册路由对象。 - 5、使用路由:通过
<router-link>
和<router-view>
。
实现:
1、在router/index.js中创建并导出router实例
2、在main.js中注册router实例到app上
3、在app.vue使用<router-view>
占位,并使用<router-link>
导航到对应路由页面
路由组件
<router-link>
<router-link>:to replace? custom? active-class? exact-active-class? v-slot?
,是 Vue Router 的导航组件,用于在SPA中生成可点击的路由链接,默认渲染为a标签。核心作用是实现无刷新页面切换,并自动处理路由激活状态。
<router-view>
<router-view>:name?,v-slot?,
,是 Vue Router 的核心组件,用于在SPA中渲染当前路由匹配的组件。它相当于一个动态占位符,根据路由规则切换显示内容。
路由重定向
createRouter():({history,routes,scrollBehavior?,...})
,是 VueRouter4 中用于 创建路由实例 的核心函数。替代了 VueRouter3 的 new VueRouter()。
- routes:
RouteRecordRaw[]
,定义路由配置的数组。路由对象 RouteRecordRaw 包含以下常见属性:- redirect:
string|object
,重定向目标。
- redirect:
示例:让路径默认跳到到首页, 并且渲染首页组件。
路由懒加载
createRouter():({history,routes,scrollBehavior?,...})
,是 VueRouter4 中用于 创建路由实例 的核心函数。替代了 VueRouter3 的 new VueRouter()。
- routes:
RouteRecordRaw[]
,定义路由配置的数组。路由对象 RouteRecordRaw 包含以下常见属性:- component:
Component|()=>import()
,对应组件或异步组件函数。
- component:
import():(modulePath)
,是 ES6 模块的动态导入语法,返回一个 Promise,允许在运行时异步加载模块。
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:
component
可以传入一个组件,也可以接收一个函数,该函数需要返回一个Promise,而import函数就是返回一个Promise。
Webpack魔法注释:
想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用命名 chunk
,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4):
路由匹配规则
静态路径匹配
静态路径匹配:直接匹配固定 URL 结构,如 /home
。
const routes = [
{ path: '/home', component: Home }, // 精确匹配 /home
{ path: '/about', component: About } // 精确匹配 /about
]
动态参数匹配
动态参数:通过 :param
捕获动态字段,参数值将解析到 $route.params
。
很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User
组件,它应该对所有用户进行渲染,但用户 ID 不同。在 Vue Router 中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数 :
1、在router中的path字段添加一个路径参数:xxx
。
2、在router-link标签的to中传入具体的参数值。
3、在目标组件中通过$route.params.xxx
访问路径参数。
匹配多个参数:可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params
上的相应字段。
正则约束匹配
正则约束匹配
正则约束匹配:在动态参数后添加 (正则表达式)
限制参数格式。
{ path: '/order/:id(\\d+)' } // 仅匹配数字 ID(如 /order/456)
{ path: '/file/:name(.*)' } // 匹配任意字符串(含斜杠)
通配符匹配和NotFound
通配符匹配::pathMatch(.*)
匹配任意路径,常用于 404 页面。
{ path: '/:pathMatch(.*)*', component: NotFound } // 末尾有*,表示解析匹配到的路由为对象
{ path: '/:pathMatch(.*)', component: NotFound } // 末尾没有*,表示不解析匹配到的路由,直接输出字符串
常规参数只匹配 url 片段之间的字符,用 /
分隔。如果我们想匹配任意路径,我们可以使用自定义的 路径参数 正则表达式,在 路径参数 后面的括号中加入 正则表达式 :
通过 $route.params.pathMatch
获取到传入的参数
在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将pathMatch
参数标记为可选可重复*。这样做是为了让我们在需要的时候,可以通过将 path
拆分成一个数组,直接导航到路由:
多参数匹配
可选参数
可选参数:通过 ?
标记参数为可选。
{ path: '/blog/:page?' } // 匹配 /blog 或 /blog/2
重复参数
重复参数:通过 *
或 +
匹配多个路径段,结果以数组形式存储。
{ path: '/sections/:chapters+' } // 匹配 /sections/a/b,chapters 为 ['a', 'b']
嵌套路由匹配
嵌套路由匹配:通过 children
定义嵌套结构,父组件需包含 <router-view>
。
{
path: '/dashboard',
component: Dashboard,
children: [
{ path: 'stats', component: Stats } // 匹配 /dashboard/stats
]
}
匹配模式控制
严格模式(strict):启用后路径末尾斜杠敏感(默认忽略)。
{ path: '/user/', strict: true } // 仅匹配 /user/,不匹配 /user
大小写敏感(sensitive):路径区分大小写。
{ path: '/Profile', sensitive: true } // 不匹配 /profile
别名
别名(alias):允许多路径映射同一组件,URL 不变化。
{ path: '/home', alias: ['/', '/main'], component: Home }
重定向
重定向(redirect):路径跳转到新地址,URL 更新。
{ path: '/old', redirect: '/new' }
匹配优先级
- 静态路径优先:精确匹配的静态路由 > 动态路由 > 通配符路由。
- 参数顺序影响:相同层级的动态路由按配置顺序匹配,先定义者优先。
获取路径参数
组件中获取路径参数的方式:
方式一:模板中: $route.params.id
方式二:选项式API中: this.$route.params.id
方式三:组合式API中: useRoute().params.id
嵌套路由
基本使用
path: '/home'
children:
path: '', name:'recommend', redirect:'/home/recommend'
path: '/home', redirect:'/home/recommend'
path: '/home/recommend'
path: 'recommend'
1、路由映射: 在router的路由映射中定义children
2、在根组件App.vue中使用<router-view>
占位。
2、在子组件User.vue中使用<router-view>
占位。
嵌套路由配置
children属性:在父路由配置中通过 children
数组定义子路由,子路由的 path
支持两种形式。
const routes = [
{
path: '/parent',
component: ParentComponent,
children: [
// 1. 相对路径:继承父路径,完整路径为 /parent/child
{ path: 'child', component: ChildComponent },
// 2. 绝对路径:独立于父路径,完整路径为 /child
{ path: '/child', component: ChildComponent }
]
}
]
动态参数继承:若父路由包含动态参数如 :id
,子路由可通过 $route.params
直接访问。
{
path: '/user/:id',
component: UserLayout,
children: [
// 子路由路径自动继承父级参数,完整路径为 /user/123/profile
{ path: 'profile', component: UserProfile }
]
}
组件模板占位
父组件中定义<router-view>
:子路由的渲染位置由父组件模板中的 <router-view>
标签决定。若未定义该标签,子路由组件不会显示。
<!-- ParentComponent.vue -->
<template>
<div>
<h2>父级布局</h2>
<router-view></router-view> <!-- 子路由在此渲染 -->
</div>
</template>
默认子路由
默认子路由:设置 path: ''
作为默认子路由,当父路径被访问时自动加载。
children: [
{ path: '', component: DefaultChild },
{ path: 'other', component: OtherChild }
]
注意:当使用''
时,需要添加一个name
属性,否则会提示警告。
当你访问 /user/eduardo
时,在 User
的 router-view
里面什么都不会呈现,因为没有匹配到嵌套路由。也许你确实想在那里渲染一些东西。在这种情况下,你可以提供一个空的嵌套路径:
路由懒加载
路由懒加载:结合动态导入提升性能。
children: [
{ path: 'stats', component: () => import('./UserStats.vue') }
]
结合UI库
结合UI库:在 Element Plus中通过菜单组件的router
属性动态激活路由。
<el-menu :default-active="$route.path" router>
<el-menu-item index="/user/detail">详情</el-menu-item>
<el-menu-item index="/user/settings">设置</el-menu-item>
</el-menu>
命名父路由
命名父路由:通过push({name: 'user-parent'})
的父路由name导航时只会导航到父路由而不导航到嵌套子路由。
注意: 重新加载页面将始终显示嵌套的子路由,因为它被视为指向路径/users/:id
的导航,而不是命名路由。
编程式导航
router.push()
router.push():(to)
,核心导航方法,用于 编程式导航到新路由,支持多种参数形式。
调用:在 Vue 实例中,你可以通过 $router
访问路由实例。因此你可以调用 this.$router.push()
。
router.push():会向 history 栈添加一个新的记录,当用户点击浏览器后退按钮时,会回到之前的 URL。
path 与 params 的冲突:如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。
router-link内部实现:
当你点击
<router-link>
时,内部会调用这个方法。由于属性
to
与router.push()
接受的对象种类相同,所以两者的规则完全相同。
返回值:router.push()
和所有其他导航方法都会返回一个 Promise,让我们可以等到导航完成后才知道是成功还是失败。
router.replace()
router.replace():(to)
,编程式导航方法,用于 替换当前浏览器历史记录中的路由,不会新增历史条目。适用于需要隐藏当前导航记录的场景,如登录后跳转,不希望用户通过返回按钮回到登录页。
对比push():它的作用类似于 router.push()
,唯一不同的是,它在导航时不会向 history 添加新记录,它取代了当前的条目。
router.go()
router.go():(n)
,全局导航方法,用于在 浏览器历史记录栈 中前进或后退指定的步数。行为类似于浏览器的前进/后退按钮。
该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)
。
动态路由
动态添加路由
router.addRoute():(parentName?,route)
,是 Vue Router 提供的动态路由管理方法,允许在运行时向路由器实例添加新的路由规则。适用于需要根据用户权限、功能模块懒加载等场景动态扩展路由表的情况。
对路由的添加通常是通过 routes 选项来完成的,但是在某些情况下,你可能想在应用程序已经运行的时候添加路由。
应用场景:根据用户不同的权限,注册不同的路由
语法:
// 动态添加一个【路由】
$router.addRoute(路由对象)
// 动态添加一个【子路由】
$router.addRoute('父路由name', 子路由对象)
示例:
动态添加一个【路由】
动态添加一个【子路由】
动态删除路由
router.removeRoute():(name)
,是 Vue Router 提供的动态路由管理方法,用于在运行时通过路由名称或addRoute()返回的移除函数来删除路由。已注册的路由规则。适用于需要根据用户权限、模块卸载等场景动态调整路由表的场景。
三种删除方式:
- 1、添加一个name相同的路由
- 2、通过removeRoute方法,传入路由的名称
- 3、通过addRoute方法的返回值回调
示例:
1、添加一个name相同的路由
2、通过removeRoute方法,传入路由的名称
3、通过addRoute方法的返回值回调
导航守卫
router.beforeEach():(guard)
,全局前置导航守卫,用于在每次路由跳转前执行自定义逻辑,如权限校验、数据预加载等。
router.afterEach():(guard)
,全局后置守卫,用于注册一个在 导航完成之后 执行的钩子函数。它不会改变导航结果,常用于执行与导航结果无关的后续处理操作,如埋点统计、页面标题更新等。
router.beforeResolve():()
,全局解析守卫,用于注册一个在 导航被确认之前 执行的钩子函数。
语法:
参数:
- to:即将要进入的路由目标对象
- from:当前导航正要离开的路由对象
- next:在Vue2中我们是通过next函数来决定如何进行跳转的【Vue3不再推荐】
返回值:
- false:取消当前导航
- undefined | 不返回:进行默认导航
- 一个路由地址:String | Object。跳转到该路由地址
注意:Vue3中利用返回值取代了Vue2中next的作用
示例: